<template>
  <div class="organizationTree-wrapper">
    <!-- 弹窗树 -->
    <div v-if="dialogShow" class="maskCenter">
      <div class="systemDialog" style="width: 424px;height: 565px;">
        <div class="dialog-header" v-winmove>
          <span class="treeTitle">{{ dialogTitle ? dialogTitle : propsParam.dialogTitle }}</span>
        </div>
        <div class="dialog-body">
          <el-input class="systemInput" placeholder="请输入内容" v-model="param.name" v-if="searchBoxShow">
            <el-button slot="append" icon="el-icon-search" @click="treeSearch"></el-button>
          </el-input>
          <!-- 异步树 -->
          <el-tree
              :indent="0"
              v-if="treeIsAsyn"
              lazy
              ref="tree"
              node-key="id"
              :props="treeProps"
              :load="loadNode"
              :show-checkbox="Boolean(checkBoxType)"
              :check-strictly="checkStrictly"
              :expand-on-click-node="false"
              icon-class="icon iconfont iconkuangjia-xiala1"
              @check="handleCheckChange"
              @node-contextmenu="openMenu"
              @node-click="handleNodeClick"
              @node-expand="handleNodeExpand"
              @node-collapse="handleNodeExpand"
          >
						<span slot-scope="{node, data}">
							<span :class="[data.icon + `${data.state===0?' disabled':''}`]"></span>
							<span @dblclick="clkDb(node, data)">{{ node.label }}</span>
						</span>
          </el-tree>
          <!-- 全加载树 -->
          <el-tree
              :indent="0"
              v-if="!treeIsAsyn"
              ref="tree"
              :props="treeProps"
              :data="treeData"
              :show-checkbox="Boolean(checkBoxType)"
              default-expand-all
              :expand-on-click-node="false"
              icon-class="icon iconfont iconkuangjia-xiala1"
              @check="handleCheckChange"
              @node-click="handleNodeClick"
              @node-expand="handleNodeExpand"
              @node-collapse="handleNodeExpand"
          >
						<span slot-scope="{node, data}">
							<span :class="[data.icon + `${data.state===0?' disabled':''}`]"></span>
							<span @dblclick="clkDb(node, data)">{{ node.label }}</span>
						</span>
          </el-tree>
        </div>
        <div class="dialog-footer right">
          <span class="systemButtonConfirm" @click="confirm">确定</span>
          <span class="systemButtonCancel" @click="cancel">取消</span>
        </div>
      </div>
    </div>
    <!-- 平面异步树 -->
    <el-tree
        class="tree"
        :indent="0"
        v-if="treeIsAsyn && !dialogShow"
        lazy
        ref="tree"
        node-key="id"
        :props="treeProps"
        :load="loadNode"
        :show-checkbox="Boolean(checkBoxType)"
        :check-strictly="checkStrictly"
        :expand-on-click-node="false"
        icon-class="icon iconfont iconkuangjia-xiala1"
        @check="handleCheckChange"
        @node-contextmenu="openMenu"
        @node-click="handleNodeClick"
        @node-expand="handleNodeExpand"
        @node-collapse="handleNodeExpand"
    >
			<span slot-scope="{node, data}">
				<span :class="[data.icon + `${data.state===0?' disabled':''}`]"></span>
				<span @dblclick="clkDb(node, data)">{{ node.label }}</span>
			</span>
    </el-tree>
    <!-- 平面全加载树 -->
    <el-tree
        :indent="0"
        v-if="!treeIsAsyn && !dialogShow"
        ref="tree"
        :props="treeProps"
        :data="treeData"
        :show-checkbox="Boolean(checkBoxType)"
        default-expand-all
        :expand-on-click-node="false"
        icon-class="icon iconfont iconkuangjia-xiala1"
        @check="handleCheckChange"
        @node-click="handleNodeClick"
        @node-expand="handleNodeExpand"
        @node-collapse="handleNodeExpand"
    >
			<span slot-scope="{node, data}">
				<span :class="[data.icon + `${data.state===0?' disabled':''}`]"></span>
				<span @dblclick="clkDb(node, data)">{{ node.label }}</span>
			</span>
    </el-tree>
    <div
        :class="[`${menuPositionTop?'dropMenu menuTop':'dropMenu'}`+ ' ' +`${menuShow?'active':''}`]"
        v-if="Boolean(dropMenuShow)"
        :style="{ top: menuTop + 'px', left: menuLeft + 'px' }"
    >
      <div v-for="item in dropMenuList" :key="item.index" @click="menuOperation(item.index)">
        <span :class="item.icon"></span>
        {{ item.label }}
      </div>
    </div>
  </div>
</template>

<script>
import {
  deptOrUserTree,
  getDeptIdByGrade,
} from '@/system/api/organization/organization'
import {roleOnceTree} from '@/system/api/organization/roleManage'
import winmove from '@/directives/winmove'

export default {
  data() {
    return {
      checkBoxType: null,
      checkStrictly: false,
      treeIsAsyn: true,
      treeData: [],
      treeURL: null,
      treeProps: {
        label: 'name',
        isLeaf: 'leaf',
        id: 'id',
        disabled: function (data, node) {
          return !data.type || data.disableCheckbox
        },
      },
      rootNode: {},
      rootResolve: null,
      param: {}, // 树参数
      checkedList: [],
      menuShow: false,
      menuTop: 0,
      menuPositionTop: false,
      menuLeft: 0,
      menuItems: [
        {
          name: '删除',
          iconPosition: 'before',
          iconname: 'delicon',
        },
      ],
    }
  },
  directives: {
    winmove,
  },
  /* 树类型 type 0-部门 1-角色 2-人员 */
  /* 树参数 propsParam */
  /* 是否异步 isAsyn 0-同步 1-异步 */
  /* 权限类型 roleType 0-全加载 1-根据分级管理员权限加载 2-根据角色业务权限加载 */
  /* 是否弹窗 dialogShow 0-平面树 1-弹窗树 */
  /* 弹窗标题 dialogTitle */

  /* 是否可选择 checkBoxShow 0-无选择框 1-多选 2-单选
   *  可选状态下：
   *  部门-树节点父子不关联
   *  人员（异步树）-部门禁止勾选
   *  人员（全加载树）-树节点父子关联
   *  角色（异步树）-路径禁止勾选
   *  角色（全加载树）-树节点父子关联
   */

  /* 是否有搜索框 searchBoxShow 0-无 1-有 */
  /* 是否显示菜单 dropMenuShow 0-无 1-有 */

  /* 	树参数 propsParam
   *  部门
   *	userFlag: false
   *	parentId: 0
   *
   *	人员
   *	userFlag: true
   *	parentId: 0
   *
   *	角色
   *	parentId: 0
   *  type: 0-全加载 1-根据分级管理员权限加载
   */
  props: {
    checkBoxShow: 0,
    type: 0,
    roleType: 0,
    dialogShow: 0,
    searchBoxShow: 0,
    dropMenuShow: 0,
    isAsyn: {type: Number, default: 1},
    dropMenuList: null,
    dialogTitle: '',
    propsParam: {
      checkBoxShow: 0,
    }, // 树参数
  },
  created() {
    // 树类型
    switch (Number(this.type)) {
      case 0:
        this.treeURL = deptOrUserTree
        this.checkStrictly = true
        break
      case 1:
        this.treeURL = roleOnceTree
        break
      case 2:
        this.treeURL = deptOrUserTree
        break
    }
    // 异步||全加载
    if (this.isAsyn === 1) {
      this.treeIsAsyn = true
    } else {
      this.treeIsAsyn = false
      this.treeURL({
        parentId: 0,
        isAsyn: false,
        userFlag: true,
      }).then((res) => {
        let arr = []
        for (let i in res.info) {
          arr.push(res.info[i])
        }
        this.setIcon(arr)
        setTimeout(() => {
          this.treeData = arr
        }, 100)
      })
    }
    this.param = this.propsParam // 树参数
    if (this.propsParam.checkBoxShow) {
      this.checkBoxType = Number(this.propsParam.checkBoxShow)
    } else {
      this.checkBoxType = Number(this.checkBoxShow)
    }
    this.globalClick()
  },
  methods: {
    // 树点击节点
    handleNodeExpand() {
      this.menuShow = false
    },
    // 树 懒加载
    async loadNode(node, resolve) {
      if (node.level === 0) {
        if (this.param.grade && this.param.grade) {
          const detail = await getDeptIdByGrade({
            grade: this.param.grade,
            deptId: this.param.parentId,
          })
          this.param.parentId = detail.info
        } else {
          this.rootResolve = resolve
          this.rootNode = node
          this.param.isAsyn = this.isAsyn === 1 ? true : false
        }
      } else this.param.parentId = node.data.id
      if (!this.param.parentId && this.param.grade) {
        return
      }
      this.treeURL(this.param).then((res) => {
        if (res.code == 200) {
          if (res.success) {
            this.treeData = res.info
            this.setIcon(this.treeData)
            return resolve(res.info)
          } else this.message(res.msg, 3)
        } else this.message(res.msg, 3)
      })
    },
    // 树节点 icon
    setIcon(arr) {
      arr.forEach((item) => {
        switch (Number(this.type)) {
            // 部门
          case 0:
            if (item.grade === 0) {
              item.icon = 'icon iconfont iconbumenxuanze-jituan'
            } else if (item.grade === 1 || item.grade === 2 || item.grade === 3) {
              item.icon = 'icon iconfont iconbumenxuanze-gongsi'
            } else if (item.grade === 4) {
              item.icon = 'icon iconfont iconbumenxuanze-bumen1'
            } else if (item.grade === 5) {
              item.icon = 'icon iconfont iconbumenxuanze-banzu1'
            }
            break
            // 人员
          case 2:
            if (item.type === 2) {
              item.icon = 'icon iconfont iconbumenxuanze-banzu'
            } else {
              if (this.isAsyn === 1) {
                item.disableCheckbox = true
              }
              if (item.grade === 0) {
                item.icon =
                    'icon iconfont iconbumenxuanze-jituan'
              } else if (item.grade === 1) {
                item.icon =
                    'icon iconfont iconbumenxuanze-gongsi'
              } else if (item.grade === 2) {
                item.icon =
                    'icon iconfont iconbumenxuanze-bumen1'
              } else if (item.grade === 3) {
                item.icon =
                    'icon iconfont iconbumenxuanze-banzu1'
              }
            }
            break
            // 角色
          default:
            item.icon =
                item.type === 1
                    ? 'icon iconfont iconbumenxuanze-jiaose'
                    : 'icon iconfont iconbumenxuanze-lujing'
        }
        if (item.children) {
          this.setIcon(item.children)
        }
      })
    },
    // 左击
    async handleNodeClick(e) {
      let data = JSON.parse(JSON.stringify(e))
      data.clickType = 1
      this.$emit('getNodeInfo', data)
      this.menuShow = false
    },
    // 右击
    async openMenu(e, data, node) {
      await this.$emit('getNodeInfo', node)
      let menuClientY = e.clientY
      let windowHeight = document.documentElement.clientHeight
      if (windowHeight - menuClientY > 200) {
        this.menuTop = e.clientY + 30
        this.menuPositionTop = false
      } else {
        let height = document.getElementsByClassName('dropMenu')[0]
            .offsetHeight
        this.menuPositionTop = true
        this.menuTop = e.clientY - height - 30
      }
      this.menuLeft = e.clientX
      this.menuShow = true
    },
    // 双击
    clkDb(node, data) {
      this.$emit('addRole', node.data)
    },
    // 勾选
    handleCheckChange(data, node) {
      let checkedList = []
      if (this.checkBoxType === 1) {
        if (this.type === 2 && this.isAsyn === 0) {
          // 只勾选人员
          node.checkedNodes.forEach((item) => {
            if (item.type === 2) {
              checkedList.push(item)
            }
          })
        } else {
          checkedList = node.checkedNodes
        }
      } else if (
          this.checkBoxType === 2 &&
          node.checkedNodes.length > 1
      ) {
        this.$refs.tree.setCheckedKeys([])
        this.$refs.tree.setChecked(data, true)
        checkedList = data
      }
      this.$emit('handleCheckChange', checkedList)
    },
    findUser(node, array) {
      if (!node.leaf) {
        node.children.forEach((element) => {
          this.findUser(element, array)
        })
      } else {
        if (node.type === 2) {
          array.push(node)
        }
      }
    },
    // 搜索
    treeSearch() {
      if (!this.param.name || this.param.name.trim() == '') {
        this.treeIsAsyn = true
        this.loadNode(this.rootNode, this.rootResolve)
      } else {
        this.param.isAsyn = false
        let datas = {
          userFlag: this.param.userFlag,
          name: this.param.name,
          isAsyn: this.param.isAsyn,
        }
        this.treeURL(datas).then((res) => {
          if (res.success) {
            this.treeData = JSON.parse(JSON.stringify(res.info))
            this.treeIsAsyn = false
          } else this.message(res.msg, 3)
        })
      }
    },
    // 弹窗 确定按钮
    confirm() {
      let checkedList = []
      let list = this.$refs.tree.getCheckedNodes()
      for (let i = 0; i < list.length; i++) {
        if (!list[i].disableCheckbox) {
          checkedList.push(list[i])
        }
      }
      this.$emit('getCheckedRoles', checkedList)
    },
    // 弹窗 取消按钮
    cancel() {
      this.$emit('treeCancel')
    },
    // 右键菜单
    menuOperation(e) {
      this.$emit('menuOperations', e)
    },
    // 节点高亮
    highLightNode(id) {
      this.$refs.tree.setCurrentKey(id)
    },
    // 节点刷新
    refreshNode(node) {
      let data = node.operationType ? node : node.parent
      if (node.level === 0 || node.rootNode) data = this.rootNode
      data.loaded = false
      data.expand() // 主动调用展开节点方法，重新查询该节点下的所有子节点
      setTimeout(() => {
        if (node.highLightId) {
          this.highLightNode(node.highLightId)
        }
      }, 100)
    },
    // 监测页面点击事件，隐藏单位树菜单
    globalClick() {
      let _this = this
      document.addEventListener('click', function (e) {
        _this.menuShow = false
        let flag = e.target.contains(
            document.getElementsByClassName('el-menu')[0]
        )
        if (!flag) return
      })
    },
  },
}
</script>

<style lang="scss" scoped>
.organizationTree-wrapper {
  .el-tree {
    color: var(--organization-tree-text-color);
    padding-left: 20px;
    background-color: transparent;

    ::v-deep.el-tree-node {
      .el-tree-node__content {
        background-color: transparent;

        .iconkuangjia-xiala1 {
          color: var(--organization-tree-dropdown-color);
          font-size: 12px;
          padding-left: 0;
          padding-right: 0;

          & ~ span span {
            &:first-child {
              margin-right: 5px;
              width: 16px;
              height: 16px;
              display: inline-block;

              &.disabled {
                color: rgba(249, 73, 99, 1);
              }
            }

            &:last-child {
              padding: 2px 8px;
            }
          }
        }

        .is-leaf.iconkuangjia-xiala1 {
          visibility: hidden;
        }
      }

      .el-tree-node__children {
        padding-left: 48px;
        overflow: visible;

        .el-tree-node {
          position: relative;

          &::before {
            content: '';
            display: block;
            width: 40px;
            height: 13px;
            border-bottom: 1px solid var(--organization-tree-line-color);
            border-bottom-left-radius: 5px;
            position: absolute;
            top: 0;
            left: 0;
            transform: translateX(-100%);
          }

          &::after {
            content: '';
            display: block;
            width: 40px;
            height: 100%;
            border-left: 1px solid var(--organization-tree-line-color);
            position: absolute;
            bottom: -10px;
            left: 0;
            transform: translateX(-100%);
          }

          &:first-child::after {
            top: 0;
            height: calc(100% + 10px);
          }

          &:last-child::after {
            top: 0;
            height: 11px;
          }
        }
      }

      &.is-current {
        .el-tree-node__content {
          background-color: transparent;

          span:last-child span:last-child {
            background-color: rgba(83, 168, 255, 1);
            color: rgba(255, 255, 255, 1);
          }
        }

        .el-tree-node__children
        .el-tree-node
        .el-tree-node__content
        span:last-child
        span:last-child {
          background-color: transparent;
          color: var(--organization-tree-text-color);
        }
      }

      &.is-expanded .el-tree-node__content {
        background-color: transparent;
      }

      /* checkbox 样式 */
      .el-checkbox__inner {
        width: 14px;
        height: 14px;
        background: rgba(238, 238, 238, 1);
        border: 1px solid var(--system-checkbox-border-color);
        border-radius: 4px;

        &:hover {
          background: rgba(255, 255, 255, 1);
          border: 1px solid rgba(29, 191, 206, 1);
        }
      }

      &.is-checked label.is-checked {
        .el-checkbox__label {
          color: var(--system-checkbox-text-color);
        }

        .el-checkbox__inner {
          width: 14px;
          height: 14px;
          background: var(--system-checkbox-bgc);
          border: 1px solid rgba(29, 191, 206, 1);
          border-radius: 4px;
          padding: 0;

          &::after {
            width: 10px;
            height: 10px;
            left: 0;
            top: 1px;
            background-color: rgba(29, 191, 206, 1);
            border-radius: 4px;
            transform: rotate(90deg);
          }
        }
      }

      .is-focus .el-checkbox__inner {
        border: 1px solid rgba(29, 191, 206, 1);
      }
    }
  }

  .systemDialog .dialog-body {
    .systemInput {
      margin-bottom: 12px;
    }

    .el-tree {
      height: calc(100% - 56px) !important;
    }
  }
}

.dropMenu {
  visibility: hidden;
  position: absolute;
  z-index: 998;
  box-shadow: 0px 0px 6px 0px rgba(68, 104, 211, 0.6);
  cursor: pointer;
  display: flex;
  flex-direction: column;

  &::before {
    display: block;
    content: '';
    width: 20px;
    height: 20px;
    position: absolute;
    top: 0;
    transform: rotate(45deg) translateY(-75%);
    background: var(--organization-dropMenu-bgc);
    box-shadow: 0px 0px 6px 0px rgba(68, 104, 211, 0.6);
    z-index: -999;
  }

  div {
    background: var(--organization-dropMenu-bgc);
    padding: 12px 20px;
    display: inline-block;
    white-space: nowrap;
    color: var(--system-button-text-color);

    .iconzengjia {
      color: rgba(132, 142, 252, 1);
    }

    .iconbiaoge-bianji {
      color: rgba(51, 153, 255, 1);
    }

    .iconbiaoge-shanchu {
      color: rgba(249, 73, 99, 1);
    }

    &:hover {
      z-index: 999;
      background: var(--organization-dropMenu-hover-bgc);
      color: rgb(255, 255, 255);

      .icon {
        color: rgb(255, 255, 255);
      }
    }

    span {
      margin-right: 13px;
    }
  }

  &.menuTop {
    &::before {
      top: 100%;
    }
  }

  &.active {
    visibility: visible;
  }
}
</style>
